import axios from "axios";
import * as vscode from "vscode";
import { login } from "@ap/user/accountsLogin";
import {
  setInsConfig,
  ConfigurationItem,
  ConfigurationKey,
} from "@ap/util/vscode/setInsConfig";
import { UserDataRootObject } from "@ap/types/config";
import { showProgress } from "@ap/util/vscode/message";

export const apiAndPCType = {
  生产环境: {
    api: "https://code-api-pc.dao3.fun/",
    pc: "https://dao3.fun/",
  },
  "预生产环境（staging）": {
    api: "https://staging-code-api-pc.dao3.fun/",
    pc: "https://staging.dao3.fun/",
  },
  "灰度环境（preprod）": {
    api: "https://preprod-code-api-pc.dao3.fun/",
    pc: "https://preprod.dao3.fun/",
  },
  "开发环境（development）": {
    api: "https://development-code-api-pc.dao3.fun/",
    pc: "https://development.dao3.fun/",
  },
};

// 导出一个引擎接口模式，用于区分生产环境和开发环境。
export let apiType: keyof typeof apiAndPCType = "生产环境";

// 定义一个URL字符串，用于指定API的地址。这个地址是用于扩展与后端服务通信的。
export let prodUrl: string = apiAndPCType[apiType].api;

export function setAPIType() {
  apiType =
    vscode.workspace
      .getConfiguration(ConfigurationItem.NODEJS_TOOL)
      .get(ConfigurationKey.BOX3_API_TYPE) ?? "生产环境";
  prodUrl = apiAndPCType[apiType].api;
}

setAPIType();

// 导出一个用户账号信息对象，方便直接访问用户账号信息。
export let userData: UserDataRootObject | null;

// 导出一个授权令牌变量，这个令牌用于授权访问受保护的资源。
export let auth: string = "";

// 导出一个用户代理字符串变量，这个字符串用于标识客户端的类型和版本。
export let ua: string | undefined = vscode.workspace
  .getConfiguration(ConfigurationItem.USER_CENTER_TOOL)
  .get<string>(ConfigurationKey.USER_AGNET);

export async function setLogin() {
  const res = await login(false);
  if (res && typeof res !== "string" && res.code === 200) {
    auth = res.data.token;
    ua =
      vscode.workspace
        .getConfiguration(ConfigurationItem.USER_CENTER_TOOL)
        .get<string>(ConfigurationKey.USER_AGNET) || undefined;
  }
}
/**
 * 设置用户授权信息。
 *
 * 该函数用于存储用户的授权上下文信息，以便在后续的操作中使用。
 * @param token {string} - 用户的授权令牌。
 * @param ua {string} - 用户代理字符串。
 */
export function setUserAuth(token: string, ua: string) {
  auth = token;
  ua = ua;
}

/**
 * 设置用户数据。
 *
 * 该函数用于存储用户数据到全局变量中，以便在应用程序的其他部分访问。
 * 它接受一个包含任意属性的对象作为参数，这个对象将被用作用户数据。
 *
 * @param context 包含用户数据的对象。
 */
export function setUserData(context?: UserDataRootObject) {
  if (context && context.data) {
    userData = context;
    vscode.window.showInformationMessage(
      `神岛账号登录成功：${context.data.nickname}(${context.data.userId})`,
      "知道了",
    );
    nPost({
      url: "https://box3lab-api.fanhat.cn/dao3lab/arenapro_count",
      data: {
        userid: context.data.userId,
        name: context.data.nickname,
      },
    });
  } else {
    if (!auth) {
      return;
    }
    userData = null;
    auth = "";
    setInsConfig(
      ConfigurationItem.USER_CENTER_TOOL,
      ConfigurationKey.ACCOUNT_TOKEN,
      "",
    );
    setInsConfig(
      ConfigurationItem.USER_CENTER_TOOL,
      ConfigurationKey.USER_AGNET,
      "",
    );
    vscode.window.showInformationMessage(`神岛账号退出成功`);
  }
}

/**
 * 设置请求头信息。
 * @param headers 一个键值对对象，用于存储请求头的信息。键是头部字段的名称，值是头部字段的值。
 * @returns 返回更新后的请求头对象。
 */
function setHeader(headers: Record<string, any>) {
  // 设置Content-Type头部，指定数据格式为JSON
  if (!headers["Content-Type"]) {
    headers["Content-Type"] = "application/json";
  }
  // 设置Authorization头部，用于身份验证。这里的auth变量应事先定义并包含有效的认证信息。
  headers["Authorization"] = auth;
  const ua = vscode.workspace
    .getConfiguration(ConfigurationItem.USER_CENTER_TOOL)
    .get<string>(ConfigurationKey.USER_AGNET);
  headers["User-Agent"] = ua || "";
  headers["X-Dao-Ua"] = ua || "";

  return headers;
}

/**
 * 使用axios库发送一个POST请求。
 * @param {Object} prop - 请求配置对象。
 * @param {string} prop.url - 请求的URL路径。
 * @param {any} prop.data - 发送的数据。
 * @param {any} [prop.headers] - 请求的头部信息，默认为空对象。
 * @returns {Promise<Record<string, any>>} - 返回一个Promise，解析为API响应的数据部分。
 */
export async function Box3Post(
  prop: {
    url: string;
    data?: any;
    headers?: Record<string, any>;
  },
  tip?: string,
): Promise<Record<string, any>> {
  let data;
  await showProgress(
    "ArenaPro：" + (tip ? "[" + tip + "] " : "") + "请求数据中，请稍后...",
    async (progress) => {
      prop.headers = setHeader(prop.headers ?? {});
      data = (
        await axios.post(prodUrl + prop.url, prop.data, {
          headers: prop.headers,
          maxContentLength: Infinity,
        })
      ).data;
    },
  );
  if (data) {
    return data;
  }
  return {};
}
/**
 * 使用axios库发送一个GET请求。
 * @param {Object} prop - 请求配置对象。
 * @param {string} prop.url - 请求的URL路径。
 * @param {any} [prop.headers] - 请求的头部信息，默认为空对象。
 * @returns {Promise<Record<string, any>>} - 返回一个Promise，解析为API响应的数据部分。
 */
export async function Box3Get(
  prop: {
    url: string;
    headers?: Record<string, any>;
  },
  tip?: string,
): Promise<Record<string, any>> {
  let data;
  await showProgress(
    "ArenaPro：" + (tip ? "[" + tip + "] " : "") + "请求数据中，请稍后...",
    async (progress) => {
      prop.headers = setHeader(prop.headers ?? {});
      data = (
        await axios.get(prodUrl + prop.url, {
          headers: prop.headers,
          maxContentLength: Infinity,
        })
      ).data;
    },
  );
  if (data) {
    return data;
  }
  return {};
}

/**
 * 使用axios库发送一个PUT请求。
 * @param {Object} prop - 请求配置对象。
 * @param {string} prop.url - 请求的URL路径。
 * @param {any} [prop.headers] - 请求的头部信息，默认为空对象。
 * @returns {Promise<Record<string, any>>} - 返回一个Promise，解析为API响应的数据部分。
 */
export async function Box3Put(
  prop: {
    url: string;
    data?: any;
    headers?: Record<string, any>;
  },
  tip?: string,
): Promise<Record<string, any>> {
  let data;
  await showProgress(
    "ArenaPro：" + (tip ? "[" + tip + "] " : "") + "请求数据中，请稍后...",
    async (progress) => {
      prop.headers = setHeader(prop.headers ?? {});
      data = (
        await axios.put(prodUrl + prop.url, prop.data, {
          headers: prop.headers,
          maxContentLength: Infinity,
        })
      ).data;
    },
  );
  if (data) {
    return data;
  }
  return {};
}

/**
 * 使用axios库发送一个Delete请求。
 * @param {Object} prop - 请求配置对象。
 * @param {string} prop.url - 请求的URL路径。
 * @param {any} [prop.headers] - 请求的头部信息，默认为空对象。
 * @returns {Promise<Record<string, any>>} - 返回一个Promise，解析为API响应的数据部分。
 */
export async function Box3Delete(
  prop: {
    url: string;
    data?: any;
    headers?: Record<string, any>;
  },
  tip?: string,
): Promise<Record<string, any>> {
  let data;
  await showProgress(
    "ArenaPro：" + (tip ? "[" + tip + "] " : "") + "请求数据中，请稍后...",
    async (progress) => {
      prop.headers = setHeader(prop.headers ?? {});
      data = (
        await axios.delete(prodUrl + prop.url, {
          data: prop.data,
          headers: prop.headers,
          maxContentLength: Infinity,
        })
      ).data;
    },
  );
  if (data) {
    return data;
  }
  return {};
}

/**
 * 使用axios库发送一个普通的GET请求。
 * @param {Object} prop - 请求配置对象。
 * @param {string} prop.url - 请求的URL路径。
 * @param {any} [prop.headers] - 请求的头部信息，默认为空对象。
 * @returns {Promise<Record<string, any>>} - 返回一个Promise，解析为API响应的数据部分。
 */
export async function get<T>(
  prop: {
    url: string;
    headers?: Record<string, any>;
  },
  tip?: string,
): Promise<T | undefined> {
  let data;
  await showProgress(
    "ArenaPro：" + (tip ? "[" + tip + "] " : "") + "请求数据中，请稍后...",
    async (progress) => {
      prop.headers = setHeader(prop.headers ?? {});
      data = (await axios.get(prop.url, { headers: prop.headers })).data;
    },
  );
  if (data) {
    return data;
  }
  return;
}

export async function nGet<T>(prop: {
  url: string;
  data?: any;
  headers?: Record<string, any>;
}): Promise<T | undefined> {
  let data;
  prop.headers = setHeader(prop.headers ?? {});
  data = (await axios.get(prop.url, { headers: prop.headers })).data;
  if (data) {
    return data;
  }
  return;
}

export async function nPost<T>(prop: {
  url: string;
  data?: any;
  headers?: Record<string, any>;
}): Promise<T | undefined> {
  let data;
  prop.headers = setHeader(prop.headers ?? {});
  data = (
    await axios.post(prop.url, prop.data, {
      headers: prop.headers,
      maxContentLength: Infinity,
    })
  ).data;
  if (data) {
    return data;
  }
  return;
}

/**
 * 将给定的HTML字符串转义为安全的字符串。
 *
 * 此函数用于将用户输入的HTML代码转义，以防止跨站脚本（XSS）攻击。
 * 它通过替换特定的HTML字符实体来实现转义，确保输出的字符串在HTML环境中安全使用。
 *
 * @param {string} unsafe - 需要转义的HTML字符串。
 * @returns {string} - 转义后的安全字符串。
 */
export function escapeHtml(unsafe: string): string {
  return unsafe
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}
